package com.game.logic.fighting.formula;

import com.coment.cfg.luban.TBPVECombatCfg;
import com.coment.cfg.luban.Tables;
import com.coment.cfg.luban.constant.AIDCFG;
import com.coment.cfg.luban.constant.FightStatus;
import com.coment.cfg.luban.fight.DamageCfg;
import com.coment.game.fight.AttributeManagerLogic;
import com.coment.game.fight.Attrs;
import com.coment.message.HurtInfo;
import com.coment.message.InjuryMessage;
import com.coment.po.roles.Roles;
import com.game.dao.user.roles.RolesDao;
import com.game.framework.lock.LooksManager;
import com.game.logic.fighting.attrs.FightingLogic;
import lombok.AccessLevel;
import lombok.Data;
import lombok.experimental.FieldDefaults;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;


/**
 * 仅进行数值计算
 */
@Data
@Slf4j
public class InjuryFormulaBase {
    public static final double DEF_K = 2.0F;
    public static final double DEF_CriticalMultiplier = 1F;
    /// 伤害次数注册
    public static final ConcurrentHashMap<String, DamageRegistration> damageFrequencyRegistration = new ConcurrentHashMap<>();
    public static TBPVECombatCfg cfg;

    static {
        cfg = Tables.cfg.get_tbpvecombatcfg();
    }

    public Roles att;

    public InjuryFormulaBase(Roles att) {
        this.att = att;
    }

    /**
     * 动态值 人打怪
     * （怪物打人，人打人，K值恒定2）
     * （K=3+怪物等级*0.005），判定若人物攻击<怪物防御，不破防在此基础上K+3
     *
     * @return K值
     */
    public double k(double defLv, Integer attCardId, double attAFAtk, double defAFDef) {
        if (attCardId > 1000) {
            log.debug("K值计算: 怪物类型，使用固定值 = {}", DEF_K);
            return DEF_K;
        } else {
            double kValue;
            boolean overwhelmed = attAFAtk >= defAFDef;
            // （K= 3 + 怪物等级*0.005），判定若人物攻击<怪物防御，不破防在此基础上K+3
            if (overwhelmed) {
                kValue = cfg.getAddArea() + defLv * cfg.getRidingArea();
                log.debug("K值计算公式-攻击({}) >= 防御({}) 触发破防，K = {} + {} * {} = {}",
                        attAFAtk, defAFDef, cfg.getAddArea(), defLv, cfg.getRidingArea(), kValue);
            } else { // 未触发
                kValue = cfg.getValue() + (double) cfg.getAdditionalArea();
                log.debug("K值计算公式-攻击({}) > 防御({})未触发破防，K{} = {}+{}", attAFAtk, defAFDef, kValue, cfg.getValue(), cfg.getAdditionalArea());
            }
            return kValue;
        }
    }

    /// 有效防御 = 防御 × (1 - 破防百分比)
    public double ed(double attAFDefBreakingPercentage, double defAFDef) {
        double effectiveDef = defAFDef - attAFDefBreakingPercentage;
        log.debug("有效防御: 防御{} * (1 - 破防百分比{}) = {}", defAFDef, attAFDefBreakingPercentage, effectiveDef);
        return effectiveDef;
    }

    /// 暴击倍率
    public double ca(boolean critRate, double criticalEffect) {
        double finalEffect = DEF_CriticalMultiplier;
        if (critRate) {
            finalEffect += criticalEffect;
            log.debug("暴击倍率计算公式: 暴击成功，倍率 = 1 + {} = {}", criticalEffect, finalEffect);
        } else {
            log.debug("暴击倍率计算公式: 未暴击，倍率 = {}", finalEffect);
        }
        return finalEffect;
    }

    /// 是否被闪避
    public boolean isDodged(double dodgeRate, double accurateRate) {
        double finalDodgeRate = dodgeRate - accurateRate;
        boolean dodged = finalDodgeRate > Math.random();

        log.debug("闪避判定: 闪避率 = {}, 准确率 = {}, 最终闪避率 = {}, 是否闪避 = {}",
                dodgeRate, accurateRate, finalDodgeRate, dodged
        );

        return dodged;
    }

    public InjuryMessage tryHurt() {
        Map<Integer, Double> atkAttrs = att.rolePanel.getAttribute();
        String attId = att.getId();
        InjuryMessage injuryMessage = new InjuryMessage();
        injuryMessage.rolesId = attId;

        // 1. 检验(攻击[生命,攻速],防御[生命])
        if (atkAttrs.get(AIDCFG.hp) < 0) {
            injuryMessage.verificationResults = 2;
            return injuryMessage;
        }

        if (!FightingLogic.canAttack(att)) {
            injuryMessage.verificationResults = 3;
            return injuryMessage;
        } else {
            // 更新攻击时间
            this.att.rolePanel.statusPanel.status.put(AIDCFG.lastAtkTime1, (double) System.currentTimeMillis());
        }
        return injuryMessage;
    }


    public HurtInfo hurt(
            RolesDao rolesDao, String rolesId
    ) {
        HurtInfo hurt;
        ReentrantLock lock = LooksManager.getWriteLock(Roles.class, rolesId);
        lock.lock();
        try {
            Roles def = rolesDao.findByIdMust(rolesId);
            Double oldHP = def.rolePanel.getAttribute().get(AIDCFG.hp);
            hurt = hurt(def, new HashSet<>(), 1.0, 0D);

            Roles roles = rolesDao.findByIdMust(rolesId);
            Double newHp = roles.rolePanel.getAttribute().get(AIDCFG.hp);
            if (!Objects.equals(oldHP, newHp)) {
                log.error("po 血量被修改 old {}-- new {}", oldHP, newHp);
            }

            rolesDao.save(def);
            return hurt;
        } finally {
            lock.unlock();
        }
    }

    public HurtInfo hurt3(
            RolesDao rolesDao, String rolesId
    ) {
        HurtInfo hurt;
        ReentrantLock lock = LooksManager.getWriteLock(Roles.class, rolesId);
        lock.lock();
        try {
            Roles def = rolesDao.findByIdMust(rolesId);
            Double oldHP = def.rolePanel.getAttribute().get(AIDCFG.hp);
            hurt = hurt(def, new HashSet<>(), 3.0, 0D);


            Roles roles = rolesDao.findByIdMust(rolesId);
            Double newHp = roles.rolePanel.getAttribute().get(AIDCFG.hp);
            if (!Objects.equals(oldHP, newHp)) {
                log.error("po 血量被修改 old {}-- new {}", oldHP, newHp);
            }

            rolesDao.save(def);
            return hurt;
        } finally {
            lock.unlock();
        }
    }

    /**
     * 攻击
     *
     * @param def              防御目标
     * @param fightStatus      战斗状态
     * @param damageMultiplier 伤害倍率
     * @param critAddValue     额外暴击加成
     * @return 伤害
     */
    public HurtInfo hurt(
            Roles def,
            Set<Integer> fightStatus,
            Double damageMultiplier,
            Double critAddValue
    ) {
        String defId = def.getId();
        HurtInfo hurtInfo = new HurtInfo();

        Map<Integer, Double> atkAttrs = att.rolePanel.getAttribute();
        Map<Integer, Double> defAttrs = def.rolePanel.getAttribute();

        hurtInfo.rolesId = def.getId();


        if (!def.isSurvive()) {
            hurtInfo.setDead(true);
            return hurtInfo;
        }


        String attId = att.getId();

        log.debug("========攻击者:{}-{},被攻击者:{}-{}", attId, att.getCardId(), defId, def.getCardId());
        // 2. 防御方判定(闪避,暴击)

        // 2.1 检查是否闪避
        if (!fightStatus.contains(FightStatus.mustHit)) {
            Double defDodgeRate = defAttrs.get(AIDCFG.dodgeRate);
            Double atkAccurateRate = atkAttrs.get(AIDCFG.accurateRate);
            if (isDodged(defDodgeRate, atkAccurateRate)) {
                log.info("{} 攻击 missed", defId);
                hurtInfo.dodged = true;
                return hurtInfo;
            }
        }

        // 2.2 检查是否暴击
        boolean critRate = fightStatus.contains(FightStatus.mustCrit) ||
                FightingLogic.isCrit(att, def);

        if (critRate) {
            hurtInfo.setCrit(true);
        }


        log.debug("================================3. 计算伤害");
        Integer attCardId = att.getCardId();


        double attAFAtk = atkAttrs.get(AIDCFG.atk);
        double defLv = defAttrs.get(AIDCFG.level);
        double defAFDef = defAttrs.get(AIDCFG.def);
        double defAFantiHurtPercentage = defAttrs.get(AIDCFG.antiHurtPercentage);
        double attAFDefBreakingPercentage = atkAttrs.get(AIDCFG.defBreakingPercentage);

        double hurt = 0D;
        double addHurt = 0D;

        double kValue = this.k(defLv, attCardId, attAFAtk, defAFDef);
        double edValue = this.ed(attAFDefBreakingPercentage, defAFDef);
        double caValue = this.ca(critRate, atkAttrs.get(AIDCFG.criticalEffect));

        //   动态判定区 = (攻击 / (攻击 + K × 有效防御))
        double dynamicJudgmentArea = attAFAtk / (attAFAtk + kValue * edValue);

        log.debug("动态判定区域：{} = 攻击{}/(攻击{} + K{} * 有效防御{})",
                dynamicJudgmentArea, attAFAtk, attAFAtk, kValue, edValue
        );

        // 减伤 =  (1-目标减伤%)
        double damageReduction = 1D - defAFantiHurtPercentage;

        // 基础伤害 = 攻击 × 动态判定区 × 暴击倍率 × 减伤
        double critAdd = caValue + critAddValue;

        hurt += attAFAtk * dynamicJudgmentArea // 基础伤害
                * critAdd  // 暴击倍率
                * damageReduction // 伤害减免
                * damageMultiplier
        ;

        // 造成附加伤害
        DamageRegistration damageRegistration = damageFrequencyRegistration.get(attId);
        if (damageRegistration != null) { // 造成附加伤害
            if (damageRegistration.cfg.hurtType == 2) {
                if (damageRegistration.time >= 1) {
                    damageRegistration.time--;
                    HashMap<String, Double> attrBonusMarkup = damageRegistration.cfg.attrBonusMarkup;
                    Attrs attrs = AttributeManagerLogic.obtainAttrs(attrBonusMarkup);
                    for (Map.Entry<Integer, Double> entry : attrs.entrySet()) {
                        Integer use = entry.getKey();
                        Double value = entry.getValue();
                        Double useValue = atkAttrs.get(use);
                        addHurt += useValue * value / 100;
                        addHurt = Math.round(addHurt * 100D) / 100D;
                    }
                } else {
                    damageFrequencyRegistration.remove(attId);
                }
            }
        }

        hurt += addHurt;

        // 保留2位小数
        hurt = Math.round(hurt * 100D) / 100D;

        if (hurt <= 1D) hurt = 1;

        // 获取面板变动值
        FightingLogic.beHarmed(def, hurt);

        hurtInfo.hp = def.rolePanel.getAttribute().get(AIDCFG.hp);

        String formatted = """
                
                ┌─ 攻击者: %s  防御者: %s
                ├─ 基础攻击: %s
                ├─ 动态判定区(攻击/(攻击+K*有效防御)): %s
                ├─ 暴击倍率: %s
                ├─ 伤害减免: %s
                ├─ 伤害倍率: %s
                ├─ 最终伤害:%s
                └─ 目标剩余血量: %s 满血为%s
                """.formatted(
                attId, defId,
                attAFAtk,
                dynamicJudgmentArea,
                critAdd,
                damageReduction,
                damageMultiplier,
                hurt,
                hurtInfo.hp,
                def.rolePanel.cultivatePanel.getValue().get(AIDCFG.hp)
        );
        log.info("伤害计算详情:{}", formatted);

        hurtInfo.hurt = hurt;
        hurtInfo.addHurt = addHurt;
        hurtInfo.shield = def.rolePanel.getAttribute().get(AIDCFG.shield);

        return hurtInfo;
    }


    /// 额外伤害注册信息
    @FieldDefaults(level = AccessLevel.PUBLIC)
    public static class DamageRegistration {
        String owner;
        DamageCfg cfg;
        int time;

        public DamageRegistration(String owner, DamageCfg cfg) {
            this.owner = owner;
            this.cfg = cfg;
            this.time = cfg.percentValue.size();
        }
    }
}